// ============================================================================
//
// LCP-net framework by Pierre CHATEL chatelp@gmail.com
// Distributed under GPLv3
// Copyright (C) THALES Land & Joint Systems, 2008, 2009. All rights reserved
//
// ============================================================================

/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl;

import java.io.File;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;

import com.thalesgroup.preferenceFramework.models.Arc;
import com.thalesgroup.preferenceFramework.models.ModelsPackage;
import com.thalesgroup.preferenceFramework.models.Node;
import com.thalesgroup.preferenceFramework.models.LCPnet.LCPnet;
import com.thalesgroup.preferenceFramework.models.LCPnet.LCPnetPackage;
import com.thalesgroup.preferenceFramework.models.LCPnet.LNode;
import com.thalesgroup.preferenceFramework.models.LCPnet.LinguisticDomain;
import com.thalesgroup.preferenceFramework.models.LCPnet.exceptions.LCPnetCombinationException;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.ArcFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.CIArcFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.Fragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.FragmentsPackage;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LCPnetFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LNodeFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LinguisticDomainFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.impl.LCPnetImpl;

/**
 * <!-- begin-user-doc --> An implementation of the model object '
 * <em><b>LC Pnet Fragment</b></em>'. <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl.LCPnetFragmentImpl#getFragmentName <em>Fragment Name</em>}</li>
 *   <li>{@link com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl.LCPnetFragmentImpl#isAntiFragment <em>Anti Fragment</em>}</li>
 *   <li>{@link com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl.LCPnetFragmentImpl#getBaseLCPnet <em>Base LC Pnet</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class LCPnetFragmentImpl extends LCPnetImpl implements LCPnetFragment {
	/**
	 * The default value of the '{@link #getFragmentName() <em>Fragment Name</em>}' attribute.
	 * <!-- begin-user-doc --> <!--
	 * end-user-doc -->
	 * @see #getFragmentName()
	 * @generated
	 * @ordered
	 */
	protected static final String FRAGMENT_NAME_EDEFAULT = "";
	/**
	 * The cached value of the '{@link #getFragmentName() <em>Fragment Name</em>}' attribute.
	 * <!-- begin-user-doc --> <!--
	 * end-user-doc -->
	 * @see #getFragmentName()
	 * @generated
	 * @ordered
	 */
	protected String fragmentName = FRAGMENT_NAME_EDEFAULT;
	/**
	 * The default value of the '{@link #isAntiFragment() <em>Anti Fragment</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #isAntiFragment()
	 * @generated
	 * @ordered
	 */
	protected static final boolean ANTI_FRAGMENT_EDEFAULT = false;
	/**
	 * The cached value of the '{@link #isAntiFragment() <em>Anti Fragment</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #isAntiFragment()
	 * @generated
	 * @ordered
	 */
	protected boolean antiFragment = ANTI_FRAGMENT_EDEFAULT;
	/**
	 * The cached value of the '{@link #getBaseLCPnet() <em>Base LC Pnet</em>}' reference.
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @see #getBaseLCPnet()
	 * @generated
	 * @ordered
	 */
	protected LCPnet baseLCPnet;

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	protected LCPnetFragmentImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return FragmentsPackage.Literals.LC_PNET_FRAGMENT;
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	public String getFragmentName() {
		return fragmentName;
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	public void setFragmentName(String newFragmentName) {
		String oldFragmentName = fragmentName;
		fragmentName = newFragmentName;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME, oldFragmentName, fragmentName));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public boolean isAntiFragment() {
		return antiFragment;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setAntiFragment(boolean newAntiFragment) {
		boolean oldAntiFragment = antiFragment;
		antiFragment = newAntiFragment;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT, oldAntiFragment, antiFragment));
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	public LCPnet getBaseLCPnet() {
		if (baseLCPnet != null && baseLCPnet.eIsProxy()) {
			InternalEObject oldBaseLCPnet = (InternalEObject)baseLCPnet;
			baseLCPnet = (LCPnet)eResolveProxy(oldBaseLCPnet);
			if (baseLCPnet != oldBaseLCPnet) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, FragmentsPackage.LC_PNET_FRAGMENT__BASE_LC_PNET, oldBaseLCPnet, baseLCPnet));
			}
		}
		return baseLCPnet;
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	public LCPnet basicGetBaseLCPnet() {
		return baseLCPnet;
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	public void setBaseLCPnet(LCPnet newBaseLCPnet) {
		LCPnet oldBaseLCPnet = baseLCPnet;
		baseLCPnet = newBaseLCPnet;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, FragmentsPackage.LC_PNET_FRAGMENT__BASE_LC_PNET, oldBaseLCPnet, baseLCPnet));
	}

	public static LCPnet getCombinedLCPnet(String fragmentPath)
			throws LCPnetCombinationException {
		// Create a resource set.
		ResourceSet resourceSet = new ResourceSetImpl();

		// Register the default resource factory -- only needed for stand-alone!
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
				.put(Resource.Factory.Registry.DEFAULT_EXTENSION,
						new XMIResourceFactoryImpl());

		// Register the packages -- only needed for stand-alone!
		ModelsPackage modelsPackage = ModelsPackage.eINSTANCE;
		LCPnetPackage lcpnetPackage = LCPnetPackage.eINSTANCE;
		FragmentsPackage fragmentPackage = FragmentsPackage.eINSTANCE;

		// Get the URI of the model file.
		URI fileURI = URI.createFileURI(new File(fragmentPath)
				.getAbsolutePath());
		Resource resource = resourceSet.getResource(fileURI, true);

		EObject obj = resource.getContents().get(0);
		if (obj instanceof LCPnetFragment) {
			LCPnetFragment fragment = (LCPnetFragment) obj;
			return fragment.getCombinedLCPnet();
		}

		throw new LCPnetCombinationException("wrong ressource type: " + obj);
	}

	public LCPnet getCombinedLCPnet() throws LCPnetCombinationException {
		this.applyFragment(null);
		return this.getBaseLCPnet();
	}

	public void applyFragment(EObject context) throws LCPnetCombinationException {
		if (this.isAntiFragment()) {
			throw new LCPnetCombinationException(
					"Usage error: deletion of an LCPNet via an AntiFragment not allowed");
		}
		
		//Warning: If it's an antiFragment, the following code will not be executed

		LCPnet baseLCPnet = this.getBaseLCPnet();

		if (this.getName() != null && !this.getName().equals("")) {
			baseLCPnet.setName(this.getName());
		}

		
		EList<Node> nodes = this.getNodes();
		if(nodes != null) {
			//Avoid list concurrent modifications
			Node[] nodes_array = nodes.toArray(new Node[]{});

			for (Node node : nodes_array) {
				if (node instanceof LNodeFragment) {
					//If lnode fragment --> apply fragment
					LNodeFragment lnodeFragment = (LNodeFragment) node;
					lnodeFragment.applyFragment(this);
				} else if (node instanceof LNode) {
					//If new lnode --> add lnode to base LCPnet
					LNode lnode = (LNode) node;
					lnode.setPreferenceNetwork(baseLCPnet);
				} else {
					throw new LCPnetCombinationException(
							"Fragment consistancy error: bad type for " + node);
				}
			}
		}

		EList<Arc> arcs = this.getArcs();
		if(arcs != null) {
			//Avoid list concurrent modifications
			Arc[] arcs_array = arcs.toArray(new Arc[]{});
			
			for (Arc arc : arcs_array) {
				if (arc instanceof ArcFragment) {
					//If arc fragment --> apply fragment
					ArcFragment arcFragment = (ArcFragment) arc;
					arcFragment.applyFragment(this);
				} else if (arc instanceof CIArcFragment) {
					//If ciarc fragment --> apply fragment
					CIArcFragment ciarcFragment = (CIArcFragment) arc;
					ciarcFragment.applyFragment(this);
				} else if (arc instanceof Arc) {
					//If new arc, iarc, ciarc --> add arc to base LCPnet
					arc.setPreferenceNetwork(baseLCPnet);
				}
				else {
					throw new LCPnetCombinationException(
							"Fragment consistancy error: bad type for " + arc);
				}
			}
		}

		LinguisticDomain utilityDomain = this.getUtilityDomain();
		if(utilityDomain != null) {
			if(utilityDomain instanceof LinguisticDomainFragment) {
				//If linguisticDomain fragment --> apply fragment
				((LinguisticDomainFragment) utilityDomain).applyFragment(this);
			} else {
				//If new linguisticDomain --> error
				throw new LCPnetCombinationException("Usage error: override of the LCPNet Utility Domain not allowed");
			}
		}
		
		EList<LinguisticDomain> linguisticDomains = this.getValueDomains();
		if(linguisticDomains != null) {
			//Avoid list concurrent modifications
			LinguisticDomain[] linguisticDomains_array = linguisticDomains.toArray(new LinguisticDomain[]{});

			for (LinguisticDomain linguisticDomain : linguisticDomains_array) {
				if(linguisticDomain instanceof LinguisticDomainFragment) {
					//If linguisticDomain fragment --> apply fragment
					((LinguisticDomainFragment) linguisticDomain).applyFragment(this);
				}
				else {
					//If new linguisticDomain --> add linguisticDomain to base LCPnet
					baseLCPnet.getValueDomains().add(linguisticDomain);
				}
			}
		}
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME:
				return getFragmentName();
			case FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT:
				return isAntiFragment() ? Boolean.TRUE : Boolean.FALSE;
			case FragmentsPackage.LC_PNET_FRAGMENT__BASE_LC_PNET:
				if (resolve) return getBaseLCPnet();
				return basicGetBaseLCPnet();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME:
				setFragmentName((String)newValue);
				return;
			case FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT:
				setAntiFragment(((Boolean)newValue).booleanValue());
				return;
			case FragmentsPackage.LC_PNET_FRAGMENT__BASE_LC_PNET:
				setBaseLCPnet((LCPnet)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME:
				setFragmentName(FRAGMENT_NAME_EDEFAULT);
				return;
			case FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT:
				setAntiFragment(ANTI_FRAGMENT_EDEFAULT);
				return;
			case FragmentsPackage.LC_PNET_FRAGMENT__BASE_LC_PNET:
				setBaseLCPnet((LCPnet)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME:
				return FRAGMENT_NAME_EDEFAULT == null ? fragmentName != null : !FRAGMENT_NAME_EDEFAULT.equals(fragmentName);
			case FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT:
				return antiFragment != ANTI_FRAGMENT_EDEFAULT;
			case FragmentsPackage.LC_PNET_FRAGMENT__BASE_LC_PNET:
				return baseLCPnet != null;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public int eBaseStructuralFeatureID(int derivedFeatureID, Class<?> baseClass) {
		if (baseClass == Fragment.class) {
			switch (derivedFeatureID) {
				case FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME: return FragmentsPackage.FRAGMENT__FRAGMENT_NAME;
				case FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT: return FragmentsPackage.FRAGMENT__ANTI_FRAGMENT;
				default: return -1;
			}
		}
		return super.eBaseStructuralFeatureID(derivedFeatureID, baseClass);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public int eDerivedStructuralFeatureID(int baseFeatureID, Class<?> baseClass) {
		if (baseClass == Fragment.class) {
			switch (baseFeatureID) {
				case FragmentsPackage.FRAGMENT__FRAGMENT_NAME: return FragmentsPackage.LC_PNET_FRAGMENT__FRAGMENT_NAME;
				case FragmentsPackage.FRAGMENT__ANTI_FRAGMENT: return FragmentsPackage.LC_PNET_FRAGMENT__ANTI_FRAGMENT;
				default: return -1;
			}
		}
		return super.eDerivedStructuralFeatureID(baseFeatureID, baseClass);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy()) return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (fragmentName: ");
		result.append(fragmentName);
		result.append(", antiFragment: ");
		result.append(antiFragment);
		result.append(')');
		return result.toString();
	}

} // LCPnetFragmentImpl
